package com.xiaotu.storage;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import com.xiaotu.common.exception.SpiderException;
import com.xiaotu.common.exception.SpiderExceptionCode;
import com.xiaotu.common.util.Constants;
import com.xiaotu.common.util.DataRedisKeyUtils;
import com.xiaotu.common.util.MathUtil;
import com.xiaotu.storage.converter.AConverter;
import com.xiaotu.storage.converter.ConverterFactory;
import com.xiaotu.storage.model.CacheDataModel;

import net.sf.json.JSONObject;

/**
 * @类名 TVRecordStorageProcessor
 * @日期 2017年2月22日
 * @作者 高海军
 * @功能 tv_record数据转储
 */
@Component("TVRecordStorageProcessor")
public class TVRecordStorageProcessor extends AHSetStorageProcessor
{
	
	private static final String[] UPDATE_FIELDS = new String[] { "playCount",
			"upCount", "downCount", "comment", "upSet", "score" };
	
	private static final Boolean[] ADD_FLAGS = new Boolean[] { true, true, true,
			true, false, false };
	
	private static final String[] UPDATE_CONVERTS = new String[] {
			AConverter.INTEGER_CONVERT, AConverter.INTEGER_CONVERT,
			AConverter.INTEGER_CONVERT, AConverter.INTEGER_CONVERT,
			AConverter.INTEGER_CONVERT, AConverter.NUMBER_CONVERT };
	
	@Override
	protected String getRedisKey(Date date)
	{
		return DataRedisKeyUtils
				.getKey(Constants.DataRedisKey.TV_NetPlay_YYYYMMDD, date);
	}
	
	/**
	 * 对各个指标进行求和或者覆盖
	 * @param targetList 当前作品不同版本
	 * @param field 指标字段
	 * @param converter 转换器
	 * @param addFlag 累加标识
	 * @return 计算结果
	 */
	protected String getFieldValue(List<JSONObject> targetList, String field,
			String converter, boolean addFlag)
	{
		boolean refresh = false;
		BigDecimal val = new BigDecimal(0);
		for (JSONObject target : targetList)
		{
			if (!target.has(field))
				continue;
			Object currVal = ConverterFactory.convert(target, field, converter,
					true);
			if (currVal instanceof Number)
			{
				BigDecimal currValue = new BigDecimal(currVal.toString());
				if (addFlag)
				{
					val = MathUtil.add(val, currValue);
					refresh = true;
				}
				else if (currValue.compareTo(val) > 0)
				{
					val = currValue;
					refresh = true;
				}
			}
		}
		
		if (refresh)
			return val.toString();
		return null;
	}
	
	/**
	 * 对多于字段进行处理
	 * @param target 目标对象
	 * @return 处理后的目标对象
	 */
	protected JSONObject getTempTarget(JSONObject target)
	{
		JSONObject temp = new JSONObject();
		temp.putAll(target);
		temp.remove("tvId");
		temp.remove("tvName");
		return temp;
	}
	
	/**
	 * 校验目标对象是否满足新的数据结构
	 * @param target 目标对象
	 * @param throwAble 是否抛异常
	 * @return 是否通过
	 */
	protected boolean validateTarget(JSONObject target, boolean throwAble)
	{
		if (target == null || target.isEmpty())
		{
			if (throwAble)
				throw new SpiderException(
						SpiderExceptionCode.DataInvalideException);
			else
				return false;
		}
		JSONObject temp = this.getTempTarget(target);
		for (Object value : temp.values())
		{
			if (!(value instanceof JSONObject))
			{
				if (throwAble)
					throw new SpiderException(
							SpiderExceptionCode.DataInvalideException);
				else
					return false;
			}
		}
		
		return true;
	}
	
	/**
	 * 获取当前作品的不同版本列表
	 * @param target 目标对象
	 * @return 版本列表
	 */
	@SuppressWarnings("unchecked")
	protected List<JSONObject> getRecordList(JSONObject target)
	{
		return new ArrayList<JSONObject>(this.getTempTarget(target).values());
	}
	
	/**
	 * 计算当前作品各个版本的总值
	 * @param target 目标对象
	 * @param throwAble 格式有问题时是否抛异常
	 * @return 总体对象
	 */
	protected JSONObject getOneTarget(JSONObject target, boolean throwAble)
	{
		if (!this.validateTarget(target, throwAble))
			return null;
		List<JSONObject> targetList = this.getRecordList(target);
		if ((targetList == null || targetList.isEmpty()))
		{
			if (throwAble)
				throw new SpiderException(
						SpiderExceptionCode.DataInvalideException);
			return null;
		}
		
		Map<String, Object> valueMap = new HashMap<String, Object>();
		for (int i = 0; i < UPDATE_FIELDS.length; i++)
		{
			String val = this.getFieldValue(targetList, UPDATE_FIELDS[i],
					UPDATE_CONVERTS[i], ADD_FLAGS[i]);
			if (StringUtils.isNotEmpty(val))
				valueMap.put(UPDATE_FIELDS[i], val);
		}
		
		JSONObject tgt = targetList.get(0);
		if (!valueMap.isEmpty())
		{
			Set<String> keys = valueMap.keySet();
			for (String key : keys)
				tgt.put(key, valueMap.get(key));
		}
		
		if (target.has("tvName"))
			tgt.put("tvName", target.get("tvName"));
		return tgt;
	}
	
	@Override
	public String process(JSONObject target, CacheDataModel cacheData,
			Date date)
	{
		JSONObject tgt = this.getOneTarget(target, true);
		
		this.validateAllNotEmpty(tgt, "resourceSiteId", "tvId", "tvName");
		this.validateOneNotEmpty(tgt, "score", "playCount", "comment",
				"upCount", "downCount", "upSet");
		
		return this.list2CSVLine(ConverterFactory.convert(tgt,
				new String[] { "resourceSiteId", "tvId", "tvName", "score",
						"playCount", "comment", "upCount", "downCount", "upSet",
						"firstTime","timestamp" },
				new String[] { AConverter.STRING_CONVERT,
						AConverter.STRING_CONVERT, AConverter.STRING_CONVERT,
						AConverter.NUMBER_CONVERT, AConverter.INTEGER_CONVERT,
						AConverter.INTEGER_CONVERT, AConverter.INTEGER_CONVERT,
						AConverter.INTEGER_CONVERT, AConverter.INTEGER_CONVERT,
						AConverter.STRING_CONVERT,AConverter.TIMESTAMP_CONVERT },
				new boolean[] { true, true, true, true, true, true, true, true,
						true, true, true, true }));
	}
	
	@Override
	public String getDataType()
	{
		return Constants.PageDataType.TV_RECORD;
	}
	
	@Override
	public String getTaskType()
	{
		return Constants.SpiderTaskType.TV_RECORD;
	}
}
